/* 
 *  Copyright (C) 2006 Dip. Ing. dell'Informazione, University of Pisa, Italy
 *  http://info.iet.unipi.it/~cng/ns2measure/ns2measure.html
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, USA
 */

/**
   project: measure
   filename: output.cc
	author: C. Cicconetti <c.cicconetti@iet.unipi.it>
	year: 2006
   affiliation:
      Dipartimento di Ingegneria dell'Informazione
	   University of Pisa, Italy
   description:
	   body of the Output class
*/

#include <output.h>

void
Output::generate ()
{
	// aliases
	const std::string hdr = configuration.getHeaderName();
	const std::string trl = configuration.getTrailerName();
	std::map<std::string, AvgMeasure>& avg = metrics.getAvgMeasures();
	std::map<std::string, DstMeasure>& dst = metrics.getDstMeasures();

	// utility variables
	bool valid;
	MetricDescAvg avgDsc;
	MetricDescDst dstDsc;
	std::ofstream os;
	std::string fileName;

	//
   // averaged measures
	//
   std::map<std::string, AvgMeasure>::iterator it = avg.begin();
   for ( ; it != avg.end() ; it++ ) {
		const std::string& name = it->first;  // alias
      AvgMeasure& m = it->second;     // alias
		
	  m.restartPopulation();
	  int id = 0;
      for ( unsigned int j = 0 ; j < m.getSize() ; j++ ) {
			id = m.getPopulationId();
			// print out the sample + conf interval
			// if the population exists and the configuration files 
			// specifies that this metric/id should be printed out
			configuration.getDescAvg (valid, avgDsc, name, id);
         if ( m.getValid(id) && valid && avgDsc.output == true ) {

				// concatenate the header and metric name to get the filename
				std::stringstream buf;
				buf << hdr << name << "." << id << ".dat";
				getline (buf, fileName);
				
				// open a new file in append mode
				os.open (fileName.c_str(), std::ios::out | std::ios::app);
				if ( ! os.is_open() ) throw *this;
				
				// write data
				os << trl << ' ' << m.getPopulation(id).mean(valid) << ' '
					<< m.getPopulation(id).confInterval(valid, avgDsc.outCL) << '\n';

				// close the output file
				os.close();
         }
		 m.nextPopulation();
      }
	  m.restartPopulation();
   }

	//
   // distribution measures
	//
   std::map<std::string, DstMeasure>::iterator jt = dst.begin();
   for ( ; jt != dst.end() ; jt++ ) {
		const std::string& name = jt->first;  // alias
      DstMeasure& m = jt->second;     // alias

      for ( unsigned int i = 0 ; i < m.getSize() ; i++ ) {
			// print out the sample + conf interval
			// if the population exists and the configuration files 
			// specifies that this metric/id should be printed out
			configuration.getDescDst (valid, dstDsc, name, i);

			// if the descriptor is not valid, restart the loop
			if ( ! valid ) continue;

			// otherwise, check the derived metrics and the pdf/cdf

			// 0 = pmf
			// 1 = cdf
			// 2 = mean
			// 3 = median
			// 4 = percentile95
			// 5 = percentile99
			for ( unsigned k = 0 ; k < 6 ; k++ ) {
				// get the submetric's name
				std::string sname;
				if ( k == 0 ) sname = "pmf";
				else if ( k == 1 ) sname = "cdf";
				else if ( k == 2 ) sname = "mean";
				else if ( k == 3 ) sname = "median";
				else if ( k == 4 ) sname = "q95";
				else if ( k == 5 ) sname = "q99";
				
				// concatenate the header and metric name to get the filename
				std::stringstream buf;
				buf << hdr << name << "_" << sname << "." << i;
				
				// for pmf/cdf add the trailer to the filename
				if ( k < 2 ) buf << "." << trl;
				buf << ".dat";
				getline (buf, fileName);

				// demultiplex the submetric descriptor
				MetricDescAvg* dsc;
				if ( k == 0 ) dsc = &dstDsc.pmf;
				else if ( k == 1 ) dsc = &dstDsc.cdf;
				else if ( k == 2 ) dsc = &dstDsc.mean;
				else if ( k == 3 ) dsc = &dstDsc.median;
				else if ( k == 4 ) dsc = &dstDsc.percentile95;
				else if ( k == 5 ) dsc = &dstDsc.percentile99;
				
				// if the output of this submetric is not required
				// then restart this loop
				if ( dsc->output == false ) continue;

				// open a new file in append mode
				// if the submetric is an averaged one, then append data
				// otherwise, the existing file, if any, is overwritten
				if ( k < 2 ) os.open (fileName.c_str(), std::ios::out);
				else os.open (fileName.c_str(), std::ios::out | std::ios::app);

				// if it is not possible to write on the file -> exception
				if ( ! os.is_open() ) throw *this;

				Population* p;
				if ( k == 0 || k == 1 ) { // pmf
					for ( unsigned int h = 0 ; h < m.getSize(i) ; h++ ) {
						if ( k == 0 ) p = &m.getPopulation(i, h);
						else p = &m.getPopulationCDF(i, h);

						if ( p->mean(valid) > 0.0 ) {
							sample_t x =
								m.getDistLower() + ( h + 1.0 ) * m.getBinSize();
							os << x << ' ' << p->mean(valid) << ' '
								<< p->confInterval(valid, dsc->outCL) << '\n';
							if ( p->mean(valid) >= 1.0 ) break;
						}
					}
				} else {
					if ( k == 2 ) p = &m.getMeanPopulation(i);
					else if ( k == 3 ) p = &m.getMedianPopulation(i);
					else if ( k == 4 ) p = &m.getPercentile95Population(i);
					else p = &m.getPercentile99Population(i);

					os << trl << ' ' << p->mean(valid) << ' '
						<< p->confInterval(valid, dsc->outCL) << '\n';
				}

				// close the output file
				os.close();
         }
      }
   }

}
